package com.draven.aspect;

import com.draven.annotation.Log;
import com.draven.entity.OperationLog;
import com.draven.service.OperationLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 操作日志切面
 */
@Aspect
@Component
public class OperationLogAspect {

    private static final Logger log = LoggerFactory.getLogger(OperationLogAspect.class);

    @Autowired
    private OperationLogService operationLogService;

    /**
     * 配置切入点，拦截带有@Log注解的方法
     */
    @Pointcut("@annotation(com.draven.annotation.Log)")
    public void logPointCut() {
    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     * @param result    返回值
     */
    @AfterReturning(pointcut = "logPointCut()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
        handleLog(joinPoint, null, result);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "logPointCut()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Exception e) {
        handleLog(joinPoint, e, null);
    }

    /**
     * 处理日志记录
     */
    private void handleLog(final JoinPoint joinPoint, final Exception e, Object result) {
        try {
            // 获取注解信息
            Log logAnnotation = getLogAnnotation(joinPoint);
            if (logAnnotation == null) {
                log.error("获取日志注解信息失败");
                return;
            }

            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes == null) {
                log.error("获取请求信息失败");
                return;
            }
            HttpServletRequest request = attributes.getRequest();

            // 获取当前用户信息
            Long userId = (Long) request.getAttribute("userId");
            String username = (String) request.getAttribute("username");
            if (userId == null) {
                log.error("获取用户ID失败");
                return;
            }
            if (username == null) {
                log.error("获取用户名失败");
                return;
            }

            log.info("开始记录操作日志: 用户ID={}, 用户名={}, 模块={}, 操作类型={}, 描述={}", 
                    userId, username, logAnnotation.module(), logAnnotation.operationType(), logAnnotation.description());

            // 创建操作日志对象
            OperationLog operationLog = new OperationLog();
            operationLog.setUserId(userId);
            operationLog.setUsername(username);
            operationLog.setModule(logAnnotation.module());
            operationLog.setOperationType(logAnnotation.operationType());
            operationLog.setDescription(logAnnotation.description());
            operationLog.setMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
            operationLog.setParams(Arrays.toString(joinPoint.getArgs()));
            operationLog.setIp(getIpAddr(request));
            operationLog.setCreateTime(new Date());

            // 设置操作状态
            if (e != null) {
                operationLog.setStatus(1);
                operationLog.setErrorMsg(e.getMessage());
            } else {
                operationLog.setStatus(0);
            }

            // 保存日志
            operationLogService.saveLog(operationLog);
            log.info("操作日志记录成功");
        } catch (Exception ex) {
            // 记录日志异常
            log.error("记录操作日志异常", ex);
        }
    }

    /**
     * 获取注解信息
     */
    private Log getLogAnnotation(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        return method.getAnnotation(Log.class);
    }

    /**
     * 获取IP地址
     */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
} 